import {Pipe, PipeTransform} from '@angular/core';
import {get} from 'lodash';

/**
 * 过滤器
 *  args:Array | filter : value
 *  args:Array | filter : {"qpath":"value"} => qpath: a.b.[0].d
 *  args:Array | filter : {[or|and],"qpath":["value","eq|gt|lt|ge|le|like|start|end"]}
 */
@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {

  transform(value: any, args?: any): any {
    if (!args) {
      return value;
    }

    // 非array不筛选
    if (!(value instanceof Array)) {
      return value;
    }
    const vals = <[any]>value;

    return vals.filter(this.createFilter(args));
  }

  createFilter(arg): (v, index) => boolean {
    if (arg instanceof Object) {
      return (arrayValue, index) => {
        let hasTrue = false;
        let hasFalse = false;
        let hasOr = false;
        for (const qpath in arg) {
          if (!arg[qpath]) {
            continue;
          }
          const val = arg[qpath];
          const arrayVal = get(arrayValue, qpath);
          if (val === arrayVal) {
            hasTrue = true;
            continue;
          }
          if (val instanceof Array) {
            const itemVal = <[any]>val;
            let q, v, o;
            if (itemVal.length === 2) {
              q = val[0];
              v = val[1];
            }
            if (itemVal.length === 3) {
              o = val[0];
              q = val[1];
              v = val[2];
              if (o === 'or') {
                hasOr = true;
              }
            }

            if (!v) {
              continue;
            }
            if (!this.operation(q, v, arrayVal)) {
              hasFalse = true;
            } else {
              hasTrue = true;
            }
          }
        }
        if (hasOr && hasTrue) {
          return true;
        }
        if (hasFalse) {
          return false;
        }
        return true;
      };
    }

    return (v, index) => {
      return v === arg;
    };
  }

  operation(q, v, arrayValue) {
    switch (q) {
      case 'eq':
        return v === arrayValue;
      case 'gt':
        return arrayValue > v;
      case 'ge':
        return arrayValue >= v;
      case 'lt':
        return arrayValue < v;
      case 'le':
        return arrayValue <= v;
      case 'like':
        return arrayValue.indexOf(v) >= 0;
      case 'start':
        return arrayValue.indexOf(v) === 0;
      case 'end':
        return arrayValue.lastIndexOf(v) === 0;
      default:
        throw new Error('not support operation : ' + q);
    }
  }

}
